#ifndef NOSAL_CORE_CORE_ERROR_DOMAIN_H_
#define NOSAL_CORE_CORE_ERROR_DOMAIN_H_

#include "nosal/core/error_code.h"
#include "nosal/core/error_domain.h"
#include "nosal/core/exception.h"

#include <cerrno>

namespace netaos {
namespace nosal {
namespace core {

/// @brief An enumeration with errors that can occur within this Functional Cluster
enum class CoreErrc : ErrorDomain::CodeType
{
    kInvalidArgument = 22,  ///< invalid argument
    kInvalidMetaModelShortname = 137,  ///< given string is not a valid model element shortname
    kInvalidMetaModelPath = 138,  ///< missing or invalid path to model element
};

/// @brief Exception type thrown for CORE errors.
class CoreException : public Exception
{
public:
    /**
     * @brief Construct a new CoreException from an ErrorCode.
     * @param err  the ErrorCode
     */
    explicit CoreException(ErrorCode err) noexcept
        : Exception(err)
    { }
};

/// @brief An error domain for nosal::core errors.
class CoreErrorDomain final : public ErrorDomain
{
    constexpr static ErrorDomain::IdType kId = 0x8000000000000014;

public:
    /// @brief Alias for the error code value enumeration
    using Errc = CoreErrc;

    /// @brief Alias for the exception base class
    using Exception = CoreException;

    /// @brief Default constructor
    constexpr CoreErrorDomain() noexcept
        : ErrorDomain(kId)
    { }

    /// @brief Return the "shortname" ApApplicationErrorDomain.SN of this error domain.
    /// @returns "Core"
    char const* Name() const noexcept override
    {
        return "Core";
    }

    /// @brief Translate an error code value into a text message.
    /// @param errorCode  the error code value
    /// @returns the text message, never nullptr
    char const* Message(ErrorDomain::CodeType errorCode) const noexcept override
    {
        Errc const code = static_cast<Errc>(errorCode);
        switch (code) {
        case Errc::kInvalidArgument:
            return "Invalid argument";
        case Errc::kInvalidMetaModelShortname:
            return "Invalid meta model shortname";
        case Errc::kInvalidMetaModelPath:
            return "Invalid meta model path";
        default:
            return "Unknown error";
        }
    }

    /// @brief Throw the exception type corresponding to the given ErrorCode.
    /// @param errorCode  the ErrorCode instance
    void ThrowAsException(ErrorCode const& errorCode) const noexcept(false) override
    {
        ifc::ThrowOrTerminate<Exception>(errorCode);
    }
};

namespace internal
{
constexpr CoreErrorDomain g_coreErrorDomain;
}

/// @brief Return a reference to the global CoreErrorDomain.
/// @returns the CoreErrorDomain
inline constexpr ErrorDomain const& GetCoreErrorDomain() noexcept
{
    return internal::g_coreErrorDomain;
}

/// @brief Create a new ErrorCode within CoreErrorDomain.
///
/// This function is used internally by constructors of ErrorCode. It is usually not
/// used directly by users.
///
/// @param code  the CoreErrorDomain-specific error code value
/// @param data  optional vendor-specific error data
/// @returns a new ErrorCode instance
///
inline constexpr ErrorCode MakeErrorCode(CoreErrc code, ErrorDomain::SupportDataType data) noexcept
{
    return ErrorCode(static_cast<ErrorDomain::CodeType>(code), GetCoreErrorDomain(), data);
}

}  // namespace core
}  // namespace nosal
}  // namespace netaos

#endif  // NOSAL_CORE_CORE_ERROR_DOMAIN_H_
